# import cProfile
# 性能分析https://www.cnblogs.com/Simon-xm/p/4171902.html

# 系统相关库
import os
import traceback
import logging
logging.basicConfig()
# UI相关库
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup

from kivy.uix.codeinput import CodeInput
from pygments.lexers.python import PythonLexer

from kivy.properties import (
    NumericProperty, StringProperty, ReferenceListProperty, ObjectProperty, ListProperty
)

from kivy.core.window import Window

# 模块库
import MatchGestrue
import main as maincli


class LoadDialog(FloatLayout):
    load = ObjectProperty(None)
    cancel = ObjectProperty(None)


class SaveDialog(FloatLayout):
    save = ObjectProperty(None)
    codeinput = ObjectProperty(None)
    cancel = ObjectProperty(None)

class EditorScreen(BoxLayout):
    spinner=ObjectProperty(None)
    index_label=ObjectProperty(None)
    index_label_bcolor=ListProperty([0,0,0,1])
    up_button=ObjectProperty(None)
    down_button=ObjectProperty(None)
    save_button=ObjectProperty(None)
    close_button=ObjectProperty(None)
    
    loadfile = ObjectProperty(None)
    savefile = ObjectProperty(None)

    codeinput=ObjectProperty(None)

    _popup=None
    _files_text=None
    _fsms_list=None
    _spinner_last=None
    _modified_set=None

    _switching=False

    def dismiss_popup(self):
        if not self._popup is None:
            self._popup.dismiss()

    def show_load(self):
        content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
        self._popup = Popup(title="Load file", content=content,
                            size_hint=(0.9, 0.9))
        self._popup.open()

    def show_save(self):
        content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
        self._popup = Popup(title="Save file", content=content,
                            size_hint=(0.9, 0.9))
        self._popup.open()

    def load(self, path, filename=None):
        if filename is None:
            filepath=path
        else:
            filepath=os.path.join(path, filename[0])
        filepath=os.path.relpath(filepath, '.')
        try:
            text=""
            with open(filepath) as stream:
                text = stream.read()
            self.add_file(filepath, text)
        except:
            traceback.print_exc()
            print('加载文件错误:'+filepath)
        self.dismiss_popup()

    def save(self, path, filename=None, filekey=None):
        if filename is None:
            filepath=path
        else:
            filepath=os.path.join(path, filename)
        filepath=os.path.relpath (filepath, '.')
        try:
            text=""
            if filekey is None:
                filekey=self.spinner.text
                text=self.codeinput.text
            else:
                text=self._files_text[filekey]
            with open(filepath, 'w') as stream:
                stream.write(text)
            logging.info('保存文件[{}]到[{}]'.format(filekey, filepath))
            # 若保存的为新建
            if self.spinner.text=='新建':
                self._files_text['新建']=""
                logging.info('清空新建内容')
                self.add_file(filepath, text)
        except:
            traceback.print_exc()
            print('保存文件错误:'+filepath)
        self.dismiss_popup()

    def on_select(self, spinner, filekey=''):
        logging.info('选择[{}]'.format(filekey))
        # print("select: {}".format(filekey))
        if filekey=='打开':
            self.resume()
            self.show_load()
        else:
            # 保存浏览次序
            if filekey in self._spinner_last:
                self._spinner_last.remove(filekey)
            self._spinner_last.insert(0, filekey)
            logging.info('保存浏览次序{}'.format(self._spinner_last))
            # 更新序号
            self.update_index(None, filekey)
            # 内容有变化时更新内容
            text=self._files_text[filekey]
            if text!=self.codeinput.text:
                self._switching=True
                self.codeinput.text=text
            logging.info('更新编辑器内容')
            

    def on_up(self, button, value=None):
        # print('UP')
        filekey = self.spinner.text
        values = self.spinner.values
        idx=values.index(filekey)
        if idx>2:
            # print(idx)
            self.update_index(idx-1)
            self.update_spinner(idx=idx, exchange_idx=idx-1, filekey=None)
            
        # self.spinner.is_open=True

    def on_down(self, button, value=None):
        # print('DOWN')
        filekey = self.spinner.text
        values = self.spinner.values
        idx=values.index(filekey)
        if idx>1 and idx<len(values)-1:
            self.update_index(idx+1)
            self.update_spinner(idx=idx, exchange_idx=idx+1, filekey=None)
            
        # self.spinner.is_open=True

    def on_save(self, button, value=None):
        # print('保存')
        if self.spinner.text=='新建':
            self.show_save()
        else:
            if self.spinner.text in self._modified_set:
                self._modified_set.discard(self.spinner.text)
                logging.info('已修改列表删除[{}]'.format(self.spinner.text))
                self.save(path=self.spinner.text, filekey=None)
                # 更新自动机
                self.update_spinner(
                    idx=self.spinner.text, 
                    filekey=self.spinner.text, 
                    is_update_fsm=True)


    def on_close(self, button, value=None):
        # print("关闭 {}".format(self.spinner.text))
        if self.spinner.text!='新建':
            self.remove(self.spinner.text)
        else:
            self._spinner_last=['新建']
            self._files_text['新建']=""
            logging.info('清空新建内容')
            if self.codeinput.text!="":
                self._switching=True
                self.codeinput.text=""
        
    def on_text(self):
        # print(self._modified_set)
        # 若非切换期修改则已编辑
        if self._switching:
            self._switching=False
        else:
            self._modified_set.add(self.spinner.text)
            logging.info('已修改内容[{}]'.format(self.spinner.text))
        self._files_text[self.spinner.text]=self.codeinput.text
    
    def update_spinner(self, idx, exchange_idx=None, filekey=None, is_update_fsm=False):
        values = self.spinner.values
        if type(idx) is str:
            idx = values.index(idx)
        fsms_list = self._fsms_list
        if not exchange_idx is None:
            values[idx], values[exchange_idx] = values[exchange_idx], values[idx]
            fsms_list[idx-2], fsms_list[exchange_idx-2] = \
                fsms_list[exchange_idx-2], fsms_list[idx-2]
            logging.info('交换文件和自动机次序[{},{}]'.format(idx-1,exchange_idx-1))
        elif not filekey is None:
            print('解析文件开始:'+filekey)
            fsms, fails=maincli.parseFSM(self._files_text[filekey], False)
            if not is_update_fsm:
                if idx<0:
                    values.append(filekey)
                    fsms_list.append(fsms)
                    logging.info('追加文件和自动机[{}]'.format(filekey))
                else:
                    values.insert(idx, filekey)
                    fsms_list.insert(idx-2, fsms)
                    logging.info('插入文件和自动机[{}][{}]'.format(idx-1,filekey))
            else:#update
                fsms_list[idx-2]=fsms
                logging.info('更新自动机[{}][{}]'.format(idx-1,filekey))
        else:
            values.pop(idx)
            fsms_list.pop(idx-2)
            logging.info('删除文件和自动机次序[{}]'.format(idx-1))
        # 根据检测范围更新
        Max_num_hands=self.config.getint('PoseStream','Max_num_hands')
        Max_num_hands=min(len(fsms_list),Max_num_hands)
        MatchGestrue.updateFSMS(fsms_list[0:Max_num_hands])

    def update_index(self, idx=None, filekey=None):
        if idx is None:
            if filekey is None:
                idx=self.spinner.values.index(self.spinner.text)
            else:
                idx=self.spinner.values.index(filekey)
        idx-=1
        self.index_label.text="序号:"+str(idx if idx>0 else 0)
        # 根据是否在检测范围改背景色
        Max_num_hands=self.config.getint('PoseStream','Max_num_hands')
        if idx>0 and idx<=Max_num_hands:
            self.index_label_bcolor[1]=0.5
        else:
            self.index_label_bcolor[1]=0
        logging.info('更新序号和标签颜色')

    def add_file(self, filekey, content=None):
        # print('add_file {} '.format(filekey))
        # 更新内容
        if content:
            self._files_text[filekey]=content
            logging.info('缓存文件内容[{}]'.format(filekey))
        # 路径不在列表
        if not filekey in self.spinner.values:
            # 添加新路径
            self.update_spinner(idx=-1, exchange_idx=None, filekey=filekey)
        # 更新路径列表选择
        self.spinner.text=filekey

    def resume(self, filekey=None):
        # print("resume {}".format(filekey))
        if filekey is None:
            # 恢复之前文件路径和内容
            self.spinner.text=self._spinner_last[0]
        else:
            # 恢复指定文件路径和内容
            self.spinner.text=filekey
    
    def remove(self, filekey):
        # print("remove {}".format(filekey))
        if not filekey in self.spinner.values:
            return
        # 清除文件数据和自动机
        idx=self.spinner.values.index(filekey)
        self.update_spinner(idx=idx, exchange_idx=None, filekey=None)
        self._files_text.pop(filekey)
        logging.info('清除缓存文件内容[{}]'.format(filekey))
        # 恢复上个路径文件
        self._spinner_last.remove(filekey)
        if self._spinner_last:
            self.resume()
        else:
            self.resume("新建")
            self._spinner_last=["新建"]
        logging.info('更新文件浏览路径[{}]'.format(self._spinner_last))
        


    def init(self, config):
        self._files_text={"新建":""}
        self._fsms_list=[]
        self._spinner_last=['新建']
        self._modified_set=set()
        self.spinner.text='新建'
        self.config=config